#include "PhysxContactReport.h"

#include "PhysicsLogic.h"
#include "Game.h"
#include "Entities/Explosion.h"
#include "Util/Physx.h"

PhysxContactReport PhysxContactReport::physxContactReport;

void PhysxContactReport::onContactNotify(NxContactPair& pair, NxU32 events) {
	const float frictionForce = pair.sumFrictionForce.magnitude();
	const float normalForce = pair.sumNormalForce.magnitude();
	const float minimumForce = 5.0f;
	NxActor* a0 = pair.actors[0];
	NxActor* a1 = pair.actors[1];
	if(normalForce > minimumForce) {
		if(a0 && a1) {
			const NxVec3& pos0 = a0->getGlobalPosition();
			const NxVec3& pos1 = a1->getGlobalPosition();
			NxVec3 posCenter;
			if(a0->getNbShapes() > 0 && a0->getShapes()[0]->isHeightField()) {
				posCenter = pos1;
			} else if(a1->getNbShapes() > 0 && a1->getShapes()[0]->isHeightField()) {
				posCenter = pos0;
			} else {
				posCenter = pos0 + (pos1 - pos0)*0.5f;
			}
			NxVec3 sourcePosition = posCenter - PhysicsLogic::GetCamera().GetPosition();
			const float soundVolumeFactor = normalForce*0.02f;
			Sound::Play((Sound::SAMPLE)(Sound::SAMPLE_STONE1+rand()%3), soundVolumeFactor, sourcePosition, PhysicsLogic::GetCameraForward());
		}
	}

	for(int i=0; i<2; ++i) {
		NxActor* pickedActor = pair.actors[i];
		if(pickedActor) {
			ActorEntity* entity = (ActorEntity*)pickedActor->userData;
			if(entity) {
				if(entity->GetType() == AET_CANNON) {
					Cannon* cannon = (Cannon*)entity;
					if(!cannon->IsDestroyed()) {
						cannon->TakeDamage(normalForce);
					}
				} else if(entity->GetType() == AET_BUILDING) {
					Building* building = (Building*)entity;
					if(!building->IsDestroyed()) {
						building->TakeDamage(normalForce);
					}
				} else if(entity->GetType() == AET_CANNON_BALL) {
					CannonBall* cannonBall = (CannonBall*)entity;
					if(cannonBall == PhysicsLogic::GetObservedCannonBall()) {
						PhysicsLogic::SetObservedCannonBall(NULL);
					}
					if(cannonBall->GetOwner()) {
						//add gold if cannon ball hits dynamic actor (not ground)
						if(a0 == pickedActor && a1->isDynamic() || a1 == pickedActor && a0->isDynamic()) {
							cannonBall->GetOwner()->AddGold(Game::GetGoldForHit());
						}
						cannonBall->SetOwner(NULL);
					}
					cannonBall->SetWind(zeroVec3);
					if(cannonBall->IsExplosive()) {
						if(!CannonBall::toDelete.Contains(cannonBall)) {
							new Explosion(cannonBall->GetActor()->getGlobalPosition());
							CannonBall::toDelete.Add(cannonBall);
						}
					}
				}
			} else {
				if(pickedActor->getNbShapes() > 0 && pickedActor->getShapes()[0]->isBox()) {
					if(normalForce > 2.0f && pickedActor->readBodyFlag(NX_BF_KINEMATIC)) {
						pickedActor->clearBodyFlag(NX_BF_KINEMATIC);
						pickedActor->addForce(pair.sumNormalForce*0.2f);
					}
				}
			}
		}
	}
}
